﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GPforRobocode
{
    

   [Serializable]
    class NTree<T>
    {
        T _node;
        LinkedList<NTree<T>> children;
        int _count;
        int _depth;
        public int Count
        {
            get { return _count; }
        }
        public T Data
        {
            get { return _node; }
        }
        public int Depth
        {
            get { return _depth; }
        }
        
        public LinkedListNode<NTree<T>> First
        {
            get { return children.First; }
        }
        public NTree(T data)
        {
            _count = 1;
            _depth = 1;
            _node = data;
            children = new LinkedList<NTree<T>>();
        }

        public void addChild(T data)
        {
            children.AddLast(new NTree<T>(data));
            _count += 1;
        }

        public void addChild(NTree<T> data)
        {
            children.AddLast(data);
            _count += data.Count;
            if (this._depth <= data._depth)
            {
                this._depth += data._depth - (this._depth - 1);
            };

        }
        public int ReplaceRec(LinkedListNode<NTree<T>> oldnode, LinkedListNode<NTree<T>> newnode)
        {
            LinkedListNode<NTree<T>> cur = children.First;
            if (cur == null) return -1;
            while (cur != children.Last.Next)
            {
                if (cur == null) return -1;
                if (cur == oldnode)
                {
                    _count -= cur.Value._count;
                    _count += newnode.Value._count;
                    children.AddAfter(cur, newnode);
                    children.Remove(cur);
                    CheckDepth();
                    return 0;
                }

                int ret = cur.Value.ReplaceRec(oldnode, newnode);
                if (ret != -1)
                {
                    return ret;
                }
                cur = cur.Next;
                if (cur == null) return -1;
            }
            return -1;
        }
        /*
        public int Replace(LinkedListNode<NTree<T>> oldnode, LinkedListNode<NTree<T>> newnode)
        {
            Console.WriteLine(DEBUG);
            LinkedListNode<NTree<T>> cur = children.First;
            if (cur == null) return -1;
            while (cur != children.Last.Next)
            {
                if (cur == null) return -1;
                if (cur == oldnode)
                {
                    _count -= cur.Value._count;
                    _count += newnode.Value._count;
                    children.AddAfter(cur, newnode);
                    children.Remove(cur);
                    CheckDepth();
                    return 0;
                }

                int ret = cur.Value.Replace(oldnode, newnode);
                if (ret != -1)
                {
                    return ret;
                }
                cur = cur.Next;
                if (cur == null) return -1;
            }
            return -1;
        }
        */
        public NTree<T> GetChild(int i)
        {
            foreach (NTree<T> n in children)
                if (--i == 0) return n;
            return null;
        }
        public LinkedListNode<NTree<T>> GetNode(int i)
        {
            int counter = i;
            LinkedListNode<NTree<T>> ret = SearchNode(ref counter);
            if (ret == null)
            {
                LinkedList<NTree<T>> temp = new LinkedList<NTree<T>>();
                temp.AddLast(this);
                ret = temp.First;
            }
            return ret;
        }

        LinkedListNode<NTree<T>> SearchNode(ref int counter)
        {

            LinkedListNode<NTree<T>> cur = children.First;
            if (cur == null) return null;
            while (cur != children.Last.Next)
            {
                if (cur == null) return null;
                --counter;
                if (counter == 0)
                {
                    return cur;
                }

                LinkedListNode<NTree<T>> ret = cur.Value.SearchNode(ref counter);
                if (ret != null)
                {
                    return ret;
                }
                cur = cur.Next;
                if (cur == null) return null;
            }
            return null;

        }
        public void CheckDepth()
        {
            if (children.Count == 0)
            {
                _depth = 1;
            }
            else
            {
                DepthRec(children.First, 2);
            }
        }
        public void DepthRec(LinkedListNode<NTree<T>> node, int temp)
        {
            if (node == null) return;
            if (temp >= GP.MAXDEPTH)
            {
                _depth = -1;
                return;
            }
            if (_depth < temp)
            {
                _depth = temp;
            }
            LinkedListNode<NTree<T>> cur = node;
            while (cur != children.Last.Next && cur != null)
            {
                DepthRec(cur.Value.First, temp + 1);
                cur = cur.Next;
            }
            return;
        }
        public void SetData(T str)
        {
            _node = str;
        }

    }
}
